Stop cursor blinking after a configurable timeout. (#353670, #352442,
authorMatthias Clasen <matthiasc@src.gnome.org>
Fri, 1 Sep 2006 02:14:30 +0000 (02:14 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Fri, 1 Sep 2006 02:14:30 +0000 (02:14 +0000)
Stop cursor blinking after a configurable timeout.
(#353670, #352442, Arjan van de Ven, Manu Cornet)

* gtk/gtksettings.c (gtk_settings_class_init): Add a
gtk-cursor-blink-timeout setting, which specifies the number
of seconds that the cursor should blink after a user interaction.
The default value is G_MAXINT to preserve the current behaviour.

* gtk/gtkentry.c (blink_cb): Stop blinking after blink-timeout
seconds.

* gtk/gtkentry.c (gtk_entry_completion_key_press)
(gtk_entry_button_press, gtk_entry_focus_in): Reset the
blink timer.

* gtk/gtktextview.c (blink_cb): Stop blinking after blink-timeout
seconds.

* gtk/gtktextview.c (gtk_text_view_key_press_event)
(gtk_text_view_button_press_event, gtk_text_view_focus_in_event):
Reset the blink timer.

ChangeLog
gtk/gtkentry.c
gtk/gtksettings.c
gtk/gtktextview.c

index d5f87d9926fce7e56b8edbae3c3a4ade334e8f28..83bf7ee06bcc449de02aea909340cbd18dc72b07 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2006-08-31  Matthias Clasen  <mclasen@redhat.com>
+
+       Stop cursor blinking after a configurable timeout.
+       (#353670, #352442, Arjan van de Ven, Manu Cornet)
+       
+       * gtk/gtksettings.c (gtk_settings_class_init): Add a 
+       gtk-cursor-blink-timeout setting, which specifies the number
+       of seconds that the cursor should blink after a user interaction.
+       The default value is G_MAXINT to preserve the current behaviour.
+
+       * gtk/gtkentry.c (blink_cb): Stop blinking after blink-timeout
+       seconds.
+
+       * gtk/gtkentry.c (gtk_entry_completion_key_press) 
+       (gtk_entry_button_press, gtk_entry_focus_in): Reset the
+       blink timer.
+
+       * gtk/gtktextview.c (blink_cb): Stop blinking after blink-timeout
+       seconds. 
+
+       * gtk/gtktextview.c (gtk_text_view_key_press_event) 
+       (gtk_text_view_button_press_event, gtk_text_view_focus_in_event): 
+       Reset the blink timer.
+       
 2006-08-31  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkprintoperation-unix.c (get_print_dialog): Don't specify
index d87047e8ab7fa90feeeecb7b2f55337b4f86f97b..acf77b86fe7504323815e7e9c5d2e008888671e8 100644 (file)
@@ -82,6 +82,7 @@ struct _GtkEntryPrivate
 {
   gfloat xalign;
   gint insert_pos;
+  guint blink_time;  /* time in msec the cursor has blinked since last user event */
 };
 
 typedef struct _GtkEntryPasswordHint GtkEntryPasswordHint;
@@ -332,6 +333,7 @@ static void         gtk_entry_state_changed            (GtkWidget      *widget,
                                                        GtkStateType    previous_state);
 static void         gtk_entry_check_cursor_blink       (GtkEntry       *entry);
 static void         gtk_entry_pend_cursor_blink        (GtkEntry       *entry);
+static void         gtk_entry_reset_blink_time         (GtkEntry       *entry);
 static void         get_text_area_size                 (GtkEntry       *entry,
                                                        gint           *x,
                                                        gint           *y,
@@ -1589,6 +1591,8 @@ gtk_entry_button_press (GtkWidget      *widget,
       (entry->button && event->button != entry->button))
     return FALSE;
 
+  gtk_entry_reset_blink_time (entry);
+
   entry->button = event->button;
   
   if (!GTK_WIDGET_HAS_FOCUS (widget))
@@ -1676,7 +1680,7 @@ gtk_entry_button_press (GtkWidget      *widget,
              entry->drag_start_y = event->y + entry->scroll_offset;
            }
          else
-           gtk_editable_set_position (editable, tmp_pos);
+            gtk_editable_set_position (editable, tmp_pos);
          break;
  
        case GDK_2BUTTON_PRESS:
@@ -1938,6 +1942,7 @@ gtk_entry_key_press (GtkWidget   *widget,
 {
   GtkEntry *entry = GTK_ENTRY (widget);
 
+  gtk_entry_reset_blink_time (entry);
   gtk_entry_pend_cursor_blink (entry);
 
   if (entry->editable)
@@ -2010,6 +2015,7 @@ gtk_entry_focus_in (GtkWidget     *widget,
                    "direction_changed",
                    G_CALLBACK (gtk_entry_keymap_direction_changed), entry);
 
+  gtk_entry_reset_blink_time (entry);
   gtk_entry_check_cursor_blink (entry);
 
   return FALSE;
@@ -5189,9 +5195,10 @@ gtk_entry_drag_data_delete (GtkWidget      *widget,
  *  - the widget has focus
  */
 
-#define CURSOR_ON_MULTIPLIER 0.66
-#define CURSOR_OFF_MULTIPLIER 0.34
-#define CURSOR_PEND_MULTIPLIER 1.0
+#define CURSOR_ON_MULTIPLIER 2
+#define CURSOR_OFF_MULTIPLIER 1
+#define CURSOR_PEND_MULTIPLIER 3
+#define CURSOR_DIVIDER 3
 
 static gboolean
 cursor_blinks (GtkEntry *entry)
@@ -5221,6 +5228,17 @@ get_cursor_time (GtkEntry *entry)
   return time;
 }
 
+static gint
+get_cursor_blink_timeout (GtkEntry *entry)
+{
+  GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (entry));
+  gint timeout;
+
+  g_object_get (settings, "gtk-cursor-blink-timeout", &timeout, NULL);
+
+  return timeout;
+}
+
 static void
 show_cursor (GtkEntry *entry)
 {
@@ -5252,11 +5270,14 @@ static gint
 blink_cb (gpointer data)
 {
   GtkEntry *entry;
+  GtkEntryPrivate *priv; 
+  gint blink_timeout;
 
   GDK_THREADS_ENTER ();
 
   entry = GTK_ENTRY (data);
-
+  priv = GTK_ENTRY_GET_PRIVATE (entry);
   if (!GTK_WIDGET_HAS_FOCUS (entry))
     {
       g_warning ("GtkEntry - did not receive focus-out-event. If you\n"
@@ -5266,18 +5287,27 @@ blink_cb (gpointer data)
   
   g_assert (GTK_WIDGET_HAS_FOCUS (entry));
   g_assert (entry->selection_bound == entry->current_pos);
-
-  if (entry->cursor_visible)
+  
+  blink_timeout = get_cursor_blink_timeout (entry);
+  if (priv->blink_time > 1000 * blink_timeout && 
+      blink_timeout < G_MAXINT/1000) 
+    {
+      /* we've blinked enough without the user doing anything, stop blinking */
+      show_cursor (entry);
+      entry->blink_timeout = 0;
+    } 
+  else if (entry->cursor_visible)
     {
       hide_cursor (entry);
-      entry->blink_timeout = g_timeout_add (get_cursor_time (entry) * CURSOR_OFF_MULTIPLIER,
+      entry->blink_timeout = g_timeout_add (get_cursor_time (entry) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
                                            blink_cb,
                                            entry);
     }
   else
     {
       show_cursor (entry);
-      entry->blink_timeout = g_timeout_add (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER,
+      priv->blink_time += get_cursor_time (entry);
+      entry->blink_timeout = g_timeout_add (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
                                            blink_cb,
                                            entry);
     }
@@ -5291,14 +5321,18 @@ blink_cb (gpointer data)
 static void
 gtk_entry_check_cursor_blink (GtkEntry *entry)
 {
+  GtkEntryPrivate *priv; 
+  
+  priv = GTK_ENTRY_GET_PRIVATE (entry);
+
   if (cursor_blinks (entry))
     {
       if (!entry->blink_timeout)
        {
-         entry->blink_timeout = g_timeout_add (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER,
+         show_cursor (entry);
+         entry->blink_timeout = g_timeout_add (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
                                                blink_cb,
                                                entry);
-         show_cursor (entry);
        }
     }
   else
@@ -5322,13 +5356,24 @@ gtk_entry_pend_cursor_blink (GtkEntry *entry)
       if (entry->blink_timeout != 0)
        g_source_remove (entry->blink_timeout);
       
-      entry->blink_timeout = g_timeout_add (get_cursor_time (entry) * CURSOR_PEND_MULTIPLIER,
+      entry->blink_timeout = g_timeout_add (get_cursor_time (entry) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER,
                                            blink_cb,
                                            entry);
       show_cursor (entry);
     }
 }
 
+static void
+gtk_entry_reset_blink_time (GtkEntry *entry)
+{
+  GtkEntryPrivate *priv; 
+  
+  priv = GTK_ENTRY_GET_PRIVATE (entry);
+  
+  priv->blink_time = 0;
+}
+
+
 /* completion */
 static gint
 gtk_entry_completion_timeout (gpointer data)
index ad93c671e5f707bd1f0530dfed8f6f4140a26e41..9b9bb517420be63d3de9d1cc2cad4e88c1c3b358 100644 (file)
@@ -64,6 +64,7 @@ enum {
   PROP_DOUBLE_CLICK_DISTANCE,
   PROP_CURSOR_BLINK,
   PROP_CURSOR_BLINK_TIME,
+  PROP_CURSOR_BLINK_TIMEOUT,
   PROP_SPLIT_CURSOR,
   PROP_THEME_NAME,
   PROP_ICON_THEME_NAME,
@@ -201,6 +202,15 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                                                GTK_PARAM_READWRITE),
                                              NULL);
   g_assert (result == PROP_DOUBLE_CLICK_DISTANCE);
+
+  /**
+   * GtkSettings:gtk-cursor-blink:
+   *
+   * Whether the cursor should blink. 
+   *
+   * Also see the gtk-cursor-blink-timeout setting, which allows 
+   * more flexible control over cursor blinking.
+   */
   result = settings_install_property_parser (class,
                                              g_param_spec_boolean ("gtk-cursor-blink",
                                                                   P_("Cursor Blink"),
@@ -212,11 +222,31 @@ gtk_settings_class_init (GtkSettingsClass *class)
   result = settings_install_property_parser (class,
                                              g_param_spec_int ("gtk-cursor-blink-time",
                                                                P_("Cursor Blink Time"),
-                                                               P_("Length of the cursor blink cycle, in milleseconds"),
+                                                               P_("Length of the cursor blink cycle, in milliseconds"),
                                                                100, G_MAXINT, 1200,
                                                                GTK_PARAM_READWRITE),
                                              NULL);
   g_assert (result == PROP_CURSOR_BLINK_TIME);
+  /**
+   * GtkSettings:gtk-cursor-blink-timeout:
+   *
+   * Time after which the cursor stops blinking, in seconds.
+   * The timer is reset after each user interaction.
+   *
+   * Setting this to zero has the same effect as setting
+   * gtk-cursor-blinks to %FALSE. 
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_int ("gtk-cursor-blink-timeout",
+                                                               P_("Cursor Blink Timeout"),
+                                                               P_("Time after which the cursor stops blinking, in seconds"),
+                                                               1, G_MAXINT, G_MAXINT,
+                                                               GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_CURSOR_BLINK_TIMEOUT);
   result = settings_install_property_parser (class,
                                              g_param_spec_boolean ("gtk-split-cursor",
                                                                   P_("Split Cursor"),
index 402b99f05e1c873886ebf8111fffab360c998bff..69eb696222fba8e71d3cb0cfa00cde7f833a2069 100644 (file)
 
 #define SPACE_FOR_CURSOR 1
 
+typedef struct _GtkTextViewPrivate GtkTextViewPrivate;
+
+#define GTK_TEXT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TEXT_VIEW, GtkTextViewPrivate))
+
+struct _GtkTextViewPrivate 
+{
+  guint blink_time;  /* time in msec the cursor has blinked since last user event */
+};
+
+
 struct _GtkTextPendingScroll
 {
   GtkTextMark   *mark;
@@ -292,6 +302,7 @@ static void     gtk_text_view_start_selection_dnd    (GtkTextView        *text_v
 static void     gtk_text_view_check_cursor_blink     (GtkTextView        *text_view);
 static void     gtk_text_view_pend_cursor_blink      (GtkTextView        *text_view);
 static void     gtk_text_view_stop_cursor_blink      (GtkTextView        *text_view);
+static void     gtk_text_view_reset_blink_time       (GtkTextView        *text_view);
 
 static void     gtk_text_view_value_changed                (GtkAdjustment *adj,
                                                            GtkTextView   *view);
@@ -1009,6 +1020,8 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
                                "move_focus", 1,
                                GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
+
+  g_type_class_add_private (gobject_class, sizeof (GtkTextViewPrivate));
 }
 
 static void
@@ -3906,6 +3919,7 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
   if (obscure)
     gtk_text_view_obscure_mouse_cursor (text_view);
   
+  gtk_text_view_reset_blink_time (text_view);
   gtk_text_view_pend_cursor_blink (text_view);
 
   return retval;
@@ -3949,6 +3963,8 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
       return FALSE;
     }
 
+  gtk_text_view_reset_blink_time (text_view);
+
 #if 0
   /* debug hack */
   if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
@@ -4090,7 +4106,9 @@ gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
   gtk_widget_queue_draw (widget);
 
   DV(g_print (G_STRLOC": focus_in_event\n"));
-  
+
+  gtk_text_view_reset_blink_time (text_view);
+
   if (text_view->cursor_visible && text_view->layout)
     {
       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
@@ -4421,9 +4439,10 @@ gtk_text_view_forall (GtkContainer *container,
   g_slist_free (copy);
 }
 
-#define CURSOR_ON_MULTIPLIER 0.66
-#define CURSOR_OFF_MULTIPLIER 0.34
-#define CURSOR_PEND_MULTIPLIER 1.0
+#define CURSOR_ON_MULTIPLIER 2
+#define CURSOR_OFF_MULTIPLIER 1
+#define CURSOR_PEND_MULTIPLIER 3
+#define CURSOR_DIVIDER 3
 
 static gboolean
 cursor_blinks (GtkTextView *text_view)
@@ -4468,6 +4487,18 @@ get_cursor_time (GtkTextView *text_view)
   return time;
 }
 
+static gint
+get_cursor_blink_timeout (GtkTextView *text_view)
+{
+  GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
+  gint time;
+
+  g_object_get (settings, "gtk-cursor-blink-timeout", &time, NULL);
+
+  return time;
+}
+
+
 /*
  * Blink!
  */
@@ -4476,12 +4507,15 @@ static gint
 blink_cb (gpointer data)
 {
   GtkTextView *text_view;
+  GtkTextViewPrivate *priv;
   gboolean visible;
+  gint blink_timeout;
 
   GDK_THREADS_ENTER ();
 
   text_view = GTK_TEXT_VIEW (data);
-  
+  priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
+
   if (!GTK_WIDGET_HAS_FOCUS (text_view))
     {
       g_warning ("GtkTextView - did not receive focus-out-event. If you\n"
@@ -4495,14 +4529,25 @@ blink_cb (gpointer data)
 
   visible = gtk_text_layout_get_cursor_visible (text_view->layout);
 
-  if (visible)
-    text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER,
-                                             blink_cb,
-                                             text_view);
-  else
-    text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER,
+  blink_timeout = get_cursor_blink_timeout (text_view);
+  if (priv->blink_time > 1000 * blink_timeout &&
+      blink_timeout < G_MAXINT/1000) 
+    {
+      /* we've blinked enough without the user doing anything, stop blinking */
+      visible = 0;
+      text_view->blink_timeout = 0;
+    } 
+  else if (visible)
+    text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
                                              blink_cb,
                                              text_view);
+  else 
+    {
+      text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
+                                               blink_cb,
+                                               text_view);
+      priv->blink_time += get_cursor_time (text_view);
+    }
 
   /* Block changed_handler while changing the layout's cursor visibility
    * because it would expose the whole paragraph. Instead, we expose
@@ -4548,7 +4593,7 @@ gtk_text_view_check_cursor_blink (GtkTextView *text_view)
            {
              gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
              
-             text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER,
+             text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
                                                        blink_cb,
                                                        text_view);
            }
@@ -4577,12 +4622,22 @@ gtk_text_view_pend_cursor_blink (GtkTextView *text_view)
       gtk_text_view_stop_cursor_blink (text_view);
       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
       
-      text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER,
+      text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER,
                                                blink_cb,
                                                text_view);
     }
 }
 
+static void
+gtk_text_view_reset_blink_time (GtkTextView *text_view)
+{
+  GtkTextViewPrivate *priv;
+
+  priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
+
+  priv->blink_time = 0;
+}
+
 
 /*
  * Key binding handlers